﻿// ********************************
// 2010.11.02
// 自动拓扑控件
// Author:卢融凯
// ********************************
#define MockRoots

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using SManage.Infrastructure;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace SManage.Control
{
    [Serializable]
    public sealed partial class AutoTopology : UserControl
    {
        private const string NodeName = "TN";
        private int _nodeNum;
        private int _zoom = 50;
        private ITopologyNode _rootNode;
        private BufferedGraphics _bufferedGraphics;
        private IPAddress _root;
        private static readonly SynchronizationContext sc = SynchronizationContext.Current;
        public event EventHandler<DeviceManageRaisedArgs> StationDeviceManageRaised;

        public IPAddress Root
        {
            get { return _root ?? (_root = IPAddress.Parse("127.0.0.1")); }
            set {
                _root = value;
            }
        }

        public Int32 Zoom {
            get { return _zoom; }
            set { _zoom = value; }
        }

        private void GetRoot()
        {
#if MockRoots
            #region Mock roots
            _rootNode = new TopologyNode
            {
                Station = new Router
                {
                    Description = "This is a Router",
                    IPAddress = IPAddress.Parse("192.168.10.1"),
                    Name = "R1",
                    SubMask = "255.255.255.0",
                },
                LinkList = new List<ITopologyNode> { 
                    new TopologyNode {
                        Station = new Switch {
                            Description = "This is a Switch",
                            IPAddress = IPAddress.Parse("192.168.10.76"),
                            Name = "S1",
                            SubMask = "255.255.128.0",
                        },
                        LinkList = new List<ITopologyNode> {
                            new TopologyNode {
                                Station = new Switch {
                                    Description = "This is a Switch",
                                    IPAddress = IPAddress.Parse("192.168.10.77"),
                                    Name = "S2",
                                    SubMask = "255.255.128.0"
                                },
                                LinkList = new List<ITopologyNode> {
                                    new TopologyNode {
                                        Station = new Computer {
                                            Description = "This is a Computer",
                                            IPAddress = IPAddress.Parse("192.168.10.100"),
                                            Name = "PC3",
                                            SubMask = "255.255.128.0"
                                        }
                                    }
                                }
                            },
                            new TopologyNode {
                                Station = new Computer {
                                    Description = "This is a Computer",
                                    IPAddress = IPAddress.Parse("192.168.10.80"),
                                    Name = "PC2",
                                    SubMask = "255.255.128.0"
                                }
                            }
                        }
                    },
                    new TopologyNode{
                        Station = new Router {
                            Description = "This is a Router",
                            IPAddress = IPAddress.Parse("192.168.10.10"),
                            Name = "R2",
                            SubMask = "255.255.255.0"
                        }
                    },
                    new TopologyNode{
                        Station = new Computer {
                            Description = "This is a Computer",
                            IPAddress = IPAddress.Parse("192.168.10.2"),
                            Name = "PC1",
                            SubMask = "255.255.255.0"
                        }
                    }
                }
            }.AssignLocation(stationPanel.Size);
            #endregion
#else
            if (Root == null) {
                _rootNode = TopologyParser.Parse(stationPanel.Size);
            }
            else {
                _rootNode = TopologyParser.Parse(Root, stationPanel.Size);
            }
#endif

        }

        public AutoTopology()
        {
            InitializeComponent();
            DoubleBuffered = true;
            var graphic = stationPanel.CreateGraphics();
            
            graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            _bufferedGraphics = BufferedGraphicsManager.Current.Allocate(graphic, stationPanel.DisplayRectangle);
            _bufferedGraphics.Graphics.Clear(BackColor);
        }

        public void RefreshTopology() {
            if (_rootNode == null)
            {
                //Task.Factory.StartNew(
                //    () => {
                //        GetRoot();
                //        sc.Post(o => DrawTopology(), null);
                //    });
                stationPanel.Controls.Clear();
                //Task.Factory
                //    .StartNew(GetRoot)
                //    .ContinueWith(t =>
                //        sc.Post(d => DrawTopology(), null))
                //    .ContinueWith(t =>
                //        sc.Post(d => OnPaint(null), null)
                //    );
                GetRoot();
                DrawTopology();
                OnPaint(null);
            }
            else {
                DrawTopology();
            } 
        }

        private void DrawTopology() {
            if (_rootNode == null) { 
                return;
            }
            DrawStation(_rootNode);
        }

        private static String GetInterfaceDesc(IList<IPAddress> list)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < list.Count(); i++) {
                sb.AppendLine(String.Format("    {0}.{1}", (i + 1), list[i]));
            }
            return sb.ToString();
        }

        private void DrawStation(ITopologyNode station) {
            var control = station as TopologyNode;
            if (control == null) {
                return;
            } 
            control.Name = NodeName + _nodeNum++;
            control.Parent = stationPanel;
            control.Move += OnStationMove;

            StationTip.SetToolTip(control.StationImage,
                String.Format(
                    "设备类型:{0}\n\n设备描述:\n{1}\n\n接口:\n{2}",
                    control.Station.Type, 
                    control.Station.Description, 
                    GetInterfaceDesc(control.InterfaceList))
                );
            control.SetText(control.Station.Name);
            stationPanel.Controls.Add(control);

            control.DeviceManageRaised -= StationDeviceManageRaised;
            control.DeviceManageRaised += StationDeviceManageRaised;
            
            foreach (var link in control.LinkList) {
                bool exist = false;
                foreach (var l in stationPanel.Controls) { 
                    if (link == l) {
                        exist = true;
                    }
                }
                if (!exist) {
                    DrawStation(link);
                }
            }
            control.Show();
            DrawLinkLine(control);
        }

        /// <summary>
        /// 绘制链路连线
        /// </summary>
        private void DrawLinkLine(ITopologyNode node)
        {
            _bufferedGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            foreach (var n in node.LinkList) {
                
                _bufferedGraphics.Graphics.DrawLine(new Pen(Brushes.Gray), node.Center, n.Center);
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (Width < 200) {
                Width = 200;
            }
            if (Height < 200) {
                Height = 200;
            }
            stationPanel.Size = new Size(Width, Height - 45);
            _bufferedGraphics = BufferedGraphicsManager.Current.Allocate(stationPanel.CreateGraphics(), stationPanel.DisplayRectangle);
            _bufferedGraphics.Graphics.Clear(BackColor);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (_needRePaint) {
                _bufferedGraphics.Graphics.Clear(BackColor);
                //ReDrawLinkLine(this._rootNode);
                ReDrawLinkLine();
                _needRePaint = false;
            }
            _bufferedGraphics.Render();
            base.OnPaint(e);
        }
        //ITopologyNode node
        private void ReDrawLinkLine() {
            foreach (var c in stationPanel.Controls) {
                DrawLinkLine(c as ITopologyNode);
            }
        }

        private bool _needRePaint;
        private void OnStationMove(object sender, EventArgs e) {
            _needRePaint = true;
            OnPaint(null);
        }

        private void ZoomBarChange(object sender, EventArgs e)
        {
            Int32 oldZoom = _zoom;
            _zoom = zoomBar.Value;
            lblZoom.Text = string.Format("{0}%", (50 + Zoom));
            ZoomTopology(50 + oldZoom, 50 + Zoom);
        }

        private void ZoomTopology(int oldZoom, int newZoom) {
            for (int i = 0; i < stationPanel.Controls.Count; i++) {
                var oldLocation = ((TopologyNode)stationPanel.Controls[i]).Location;
                var initLocation = new Point(oldLocation.X / oldZoom * 100, oldLocation.Y / oldZoom * 100);
                var newLocation = new Point(initLocation.X * newZoom / 100, initLocation.Y * newZoom / 100);
                ((TopologyNode)stationPanel.Controls[i]).Location = newLocation;

                //var oldSize = ((TopologyNode)stationPanel.Controls[i]).Size;
                //var initSize = new Size(oldSize.Width / oldZoom * 100, oldSize.Height / oldZoom * 100);
                //var newSize = new Size(oldSize.Width * newZoom / 100, oldSize.Height * newZoom / 100);
                //((TopologyNode)stationPanel.Controls[i]).Size = newSize;
            }
            _needRePaint = true;
            OnPaint(null);
        }

        private void btnRefresh_Click(object sender, EventArgs e) {
            RefreshTopology();
        }

        private void btnFinding_Click(object sender, EventArgs e) {
            _rootNode = null;
            RefreshTopology();
        }

        //private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
        //    var sc = WindowsFormsSynchronizationContext.Current;
        //    if (sc == null) {
        //        return callback;
        //    }

        //    return asyncResult => sc.Post(
        //        result => callback((IAsyncResult)result),
        //        asyncResult);
        //}
        public AutoTopology RecoveryTopology() {
            var serializer = new BinaryFormatter();
            AutoTopology topology = new AutoTopology();
            if (!Directory.Exists("Data")) {
                Directory.CreateDirectory("Data");
            }
            if (!File.Exists(@"Data\Topology.bin")) {
                return new AutoTopology();
            }
            using (var stream = new FileStream(@"Data\Topology.bin", FileMode.Open)) {
                topology = (AutoTopology)serializer.Deserialize(stream);
            }
            return topology;
        }

        public void SaveTopology(AutoTopology topology) {
            var serializer = new BinaryFormatter();
            if (!Directory.Exists("Data")) {
                Directory.CreateDirectory("Data");
            }
            using (var stream = new FileStream(@"Data\Topology.bin", FileMode.Create)) {
                serializer.Serialize(stream, topology);
            }
        }

        private void tbnSaveTopology_Click(object sender, EventArgs e) {
            try {
                DialogShow(new SaveFileDialog(),
                    () => DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss"),
                    path =>
                    {
                        var serializer = new BinaryFormatter();
                        using (var stream = new FileStream(path, FileMode.Create)) {
                            serializer.Serialize(stream, _rootNode);
                        }
                    });
            } catch(Exception ex) {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void tbnLoadTopology_Click(object sender, EventArgs e) {
            try {
                DialogShow(new OpenFileDialog(),
                    () => null,
                    path =>
                    {
                        var serializer = new BinaryFormatter();
                        using (var stream = new FileStream(path, FileMode.Open)) {
                            //try {
                            //    var controls = (ControlCollection)serializer.Deserialize(stream);
                            //    foreach (System.Windows.Forms.Control c in controls) {
                            //        this.Controls.Add(c);
                            //    }
                            //} catch {
                            //    throw new InvalidOperationException("拓扑文件异常，请检查！");
                            //}
                            var a = serializer.Deserialize(stream);
                            _rootNode = (ITopologyNode)a;
                            stationPanel.Controls.Clear();
                            
                            RefreshTopology();
                            _needRePaint = true;
                            OnPaint(null);
                        }
                    });
            } catch (Exception ex) {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void DialogShow(FileDialog dialog, Func<String> showingAction,Action<String> showedAction) {
            if (!Directory.Exists("Data")) {
                Directory.CreateDirectory("Data");
            }
            
            var directory = Directory.GetCurrentDirectory();            
            dialog.Filter = @"topology files (*.tpg)|*.tpg|binary files (*.bin)|*.bin|All files (*.*)|*.*";
            dialog.InitialDirectory = directory + @"\Data";
            dialog.RestoreDirectory = true;
            dialog.FileName = showingAction();

            if (dialog.ShowDialog() == DialogResult.OK) {
                showedAction(dialog.FileName);
            }            
        }
    }
}
